package controllers

import java.util.Date
import java.util.UUID
import scala.collection.mutable.StringBuilder
import play.api.libs.iteratee.Enumerator
import play.api.mvc.Action
import play.api.mvc.AnyContent
import play.api.mvc.BodyParser
import play.api.mvc.Codec
import play.api.mvc.Controller
import play.api.mvc.Request
import play.api.mvc.Result
import play.api.Logger
import transcoding.TranscodeProcessManager

object Application extends Controller {

  implicit val myCustomCharset = Codec.javaSupported("UTF-8")
  LibraryManager

  private def Do(f: => Result): Action[play.api.mvc.AnyContent] = Do(parse.anyContent)(_ => f)
  private def Do[A](bp: BodyParser[A], f: => Result): Action[A] = Do(bp)(_ => f)
  private def Do[AnyContent](f: Request[play.api.mvc.AnyContent] => Result): Action[play.api.mvc.AnyContent] =
    Do(parse.anyContent)(f)
  private def Do[A](bp: BodyParser[A])(f: Request[A] => Result) = {
    Action(bp) {
      request =>
        var t: Date = null
        if (Logger.isDebugEnabled) {
          Logger.debug("Calling action for " + request.path)
          t = new Date()
        }
        try {
          f(request)
        } finally {
          if (Logger.isDebugEnabled) {
            Logger.debug("Time taken (milliseconds): %d".format(new Date().getTime() - t.getTime()))
          }
        }

    }
  }

  def dispatchTo(target: String): Action[AnyContent] = {
    try {
      val m = this.getClass().getMethod(target)
      val action = m invoke this
      action.asInstanceOf[Action[AnyContent]]
    } catch {
      case t => {
        val errorMessage = "Could not find %s".format(target)
        Logger.error(errorMessage, t)
        Do { (BadRequest(errorMessage)) }
      }
    }
  }

  def index = Action {
    Ok(views.html.index("Your new application is ready."))
  }

  def view_flash = Do {
    request =>
      val fileID = request.queryString.getOrElse("fileID", Seq()).fold("")((a, b) => a + b)
      LibraryManager.getMediaLibrary match {
        case Some(library) =>

          val videoLib = library.get(transcoding.Video)
          val mf = if (videoLib == null) null else videoLib.get(fileID.toInt)

          if (mf != null) {
            val title = mf.mainMediaFile.filePath.replace(LibraryManager.getLibraryDir, "")
            Ok(views.html.flash_player(mf.mainMediaFile, Map("playerID" -> "flash", "title" -> title, "fileID" -> fileID)))
          } else
            NotFound("Could not find the video requested.")

        case None => BadRequest
      }
  }

  def listFiles = Do {
    import collection.JavaConversions._
    val html = new StringBuilder()
    LibraryManager.getMediaLibrary match {
      case Some(library) =>

        for (entry <- library.entrySet) {

          entry.getKey match {
            case transcoding.Other =>

            case _ =>
              html append entry.getKey.toString
              val innerHTML = new StringBuilder("")
              for (mediaEntry <- entry.getValue.entrySet) {
                innerHTML append <li><a href={ routes.Application.dispatchTo("view_flash?fileID=" + mediaEntry.getKey).url }>{ mediaEntry.getValue.mainMediaFile.filePath }</a></li>
              }
              html append ("<div><ul>%s</ul></div>".format(innerHTML))
          }

        }
      case None => html append (<h2>Library currently empty</h2>)
    }
    Ok(html.toString).as(HTML)
  }

  def ps = {
    import collection.JavaConversions._
    Do {
      Ok(TranscodeProcessManager.activeProcessesMap.entrySet.map(
        entry => {
          <p>{ entry.getKey }</p> +
            entry.getValue.map(
              tp => tp.procInfo.toString + " - , can cancel? " + tp.isCancellable).toString
        }).toString)
    }
  }

  def stream = {
    Do {
      request =>
        Logger.debug(request.queryString.toString)
        Logger.debug(request.session.toString)

        val fileParam = request.queryString.getOrElse("fileID", List())
        if (fileParam.eq(""))
          BadRequest("Media not found")
        else {
          val fileID = fileParam.fold("")((a, b) => a ++ b).toInt
          val reqID = request.session.get("reqID") match {
            case Some(id) => transcoding.TranscoderUtil.stopIfActive(id); id
            case _ => UUID.randomUUID.toString
          }

          LibraryManager.getMediaFile(fileID) match {
            case None => NotFound

            case Some(mfm) =>
              Logger.debug("Streaming file: %s".format(mfm.mainMediaFile.filePath))

              transcoding.TranscoderUtil(mfm, request, reqID) match {
                case None => NotFound
                case Some((stream, mf)) =>
                  val dataContent: Enumerator[Array[Byte]] = Enumerator.fromStream(stream)
                  Ok.stream(content = dataContent).withHeaders((CONTENT_TYPE -> mf.mimeType))
                    .withSession(("reqID", reqID))
              }

          }
        }
    }
  }
}
